import cv2
import os
import sys
import ctypes
from ctypes import *
from ENGLISH import CAPTION
from PyQt5.QtWidgets import QFileDialog,QMessageBox
from PyQt5.QtGui import QFont
import configparser
import numpy as np
from  mylibs import ocr
sys.setrecursionlimit(10000)
__appname__ = 'proxima'
FONTSTR = 'Arial'
APPFONT = QFont(FONTSTR)
FONT_SIZE1 = 15
FONT_SIZE2 = 12
FONT_SIZE3 = 10

class rect2i(ctypes.Structure):
    _fields_ = [("x", ctypes.c_int),
              ("y", ctypes.c_int),
              ("width", ctypes.c_int),
              ("height", ctypes.c_int)]

class ImageDib(ctypes.Structure):
    _fields_ = [("pBuffer",ctypes.POINTER(ctypes.c_uint8)),
              ("iWidth", ctypes.c_int),
              ("iHeight", ctypes.c_int),
              ("iBit", ctypes.c_int),
              ("angle",ctypes.c_double),
                ]

class ResultPoint2d(ctypes.Structure):
    _fields_ = [("x", ctypes.c_double),
                ("y", ctypes.c_double),
                ("angle", ctypes.c_double),
                ("score", ctypes.c_double),
                ("scale", ctypes.c_double)]
class drawRect(object):
    def __init__(self,imgPath):
        self.tempdll = None
        self.model = None
        self.doublemodel = None
        self.img2 = None
        self.img3 = None
        self.boxes = []
        self.point1 = None
        self.point2 = None
        self.lineColor = (0, 0, 200)
        self.pointWidth = 1
        self.lineWidth = 2
        self.imgPath = imgPath

        if self.imgPath.endswith('shm'):
            if 'doubleTemplate1' in self.imgPath:
                self.read2Model(self.imgPath)
            else:
                self.read1Model(self.imgPath)
        elif self.imgPath.split('.')[-1] in ['png','jpg','jpeg','bmp','tif','ico']:
            self.imgName = os.path.basename(self.imgPath)
            self.img = cv2.imread(self.imgPath)
            if self.imgPath == None and self.imgPath == '':
                QMessageBox.information(None, 'Remander', "The image is empty,please try again")
                return
            cv2.namedWindow(self.imgName, cv2.WINDOW_NORMAL)
            self.img3 = self.img.copy()
            cv2.setMouseCallback(self.imgName, self.on_mouse)
            cv2.imshow(self.imgName, self.img3)
            cv2.waitKey(0)

    def on_mouse(self,event, x, y, flags, param):

        self.img2 = self.img3.copy()
        if event == cv2.EVENT_LBUTTONDOWN:
            self.point1 = (x,y)
            cv2.circle(self.img2, self.point1, self.pointWidth, self.lineColor, self.lineWidth)
        elif event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON):
            cv2.rectangle(self.img2, self.point1, (x,y), (255,0,0), self.lineWidth)
            cv2.imshow(self.imgName, self.img2)

        elif event == cv2.EVENT_LBUTTONUP :
            self.point2 = (x,y)
            cv2.rectangle(self.img2, self.point1, self.point2, self.lineColor, self.lineWidth)
            cv2.imshow(self.imgName, self.img2)
            min_x = min(self.point1[0],self.point2[0])
            min_y = min(self.point1[1],self.point2[1])
            width = abs(self.point1[0] - self.point2[0])
            height = abs(self.point1[1] -self.point2[1])
            box = [min_x,min_y,width,height]
            self.boxes.append(box)
            cv2.rectangle(self.img2,(box[0],box[1]),(box[0]+box[2],box[1]+box[3]),self.lineColor, self.lineWidth)
            cv2.imshow(self.imgName,self.img2)
            self.img3=self.img2
        elif event == cv2.EVENT_RBUTTONDOWN:
            self.img3 = self.img.copy()
            if len(self.boxes) > 0:
                self.boxes.pop(-1)
            for box in self.boxes:
                cv2.rectangle(self.img3,(box[0],box[1]),(box[0]+box[2],box[1]+box[3]),self.lineColor, self.lineWidth)
            cv2.imshow(self.imgName, self.img3)
        elif cv2.waitKeyEx()==13:
            cv2.destroyWindow(self.imgName)
            if len(self.boxes)==1:
                if param =='findAngle':
                    return
                elif param == 'ocr':
                     return
                else:
                    self.creat1Model(self.imgPath)
            elif len(self.boxes)==2:
                self.creat2Model()
            else:
                return

    def creat1Model(self,imgPath):
        if self.model != None:
            self.clear1Model(self.model)
        if self.tempdll ==None:
            self.tempdll = ctypes.windll.LoadLibrary(r"templatelocate.dll")
        self.tempdll.InitShapeModel.restype = c_void_p
        self.model = self.tempdll.InitShapeModel()
        self.tempdll.createShapeModel_Path.restype = c_bool
        img1Path = bytes(imgPath,'utf-8')
        rect = rect2i()
        box = self.boxes[0]
        rect.x = box[0]
        rect.y = box[1]
        rect.width = box[2]
        rect.height = box[3]
        resultP = ResultPoint2d()
        self.tempdll.createShapeModel_Path(c_void_p(self.model),img1Path,rect,ctypes.byref(resultP),c_double(0.0),c_double(360.0))
        self.save1Model()

    def clear1Model(self,model):
        if self.tempdll ==None:
            self.tempdll = ctypes.windll.LoadLibrary(r"templatelocate.dll")
        self.tempdll.ClearShapeModel.restype = c_voidp
        self.tempdll.ClearShapeModel(c_voidp(model))

    def save1Model(self):
        if self.tempdll == None:
            self.tempdll = ctypes.windll.LoadLibrary(r"templatelocate.dll")
        self.tempdll.SaveShapeModel.restype = c_bool
        caption = CAPTION % __appname__
        filename = QFileDialog.getSaveFileName(None, caption, '.', 'File (*.shm)')[0]
        if filename == None or filename == '':
            return
        path = bytes(filename,'utf-8')
        self.tempdll.SaveShapeModel(path,ctypes.c_void_p(self.model))

    def read1Model(self,path):
        if self.model != None:
            self.clear1Model(self.model)
        if self.tempdll ==None:
            self.tempdll = ctypes.windll.LoadLibrary(r"templatelocate.dll")
        self.tempdll.InitShapeModel.restype = c_void_p
        self.model = self.tempdll.InitShapeModel()
        self.tempdll.ReadShapeModel.restype = c_bool
        path = bytes(path,'utf-8')
        self.tempdll.ReadShapeModel(path,c_void_p(self.model))

    def getLabelAngle(self,imgpath):
        if self.tempdll == None:
            self.tempdll = ctypes.windll.LoadLibrary(r"templatelocate.dll")
        self.tempdll.findShapeModel_Path.restype = c_bool
        self.imgName='Find angle'
        cv2.namedWindow(self.imgName,cv2.WINDOW_NORMAL)
        self.img = cv2.imread(imgpath)
        self.img3 = self.img.copy()
        cv2.setMouseCallback(self.imgName, self.on_mouse,'findAngle')
        cv2.imshow(self.imgName, self.img3)
        cv2.waitKey(0)
        rect = rect2i()
        box = self.boxes[0]
        rect.x = box[0]
        rect.y = box[1]
        rect.width = box[2]
        rect.height = box[3]
        imgdib = ImageDib()
        bimgPath = bytes(imgpath,'utf-8')
        resultP = ResultPoint2d()
        self.tempdll.findShapeModel_Path(c_void_p(self.model),bimgPath,rect,ctypes.byref(resultP),ctypes.byref(imgdib),c_double(0.0),c_double(360.0),c_double(0.6))
        imgAngle = np.array(
            np.fromiter(imgdib.pBuffer, dtype=np.uint8, count=int(imgdib.iWidth * imgdib.iHeight * imgdib.iBit / 8)))
        self.boxes=[]
        imgAngle = imgAngle.reshape((imgdib.iHeight, imgdib.iWidth,int(imgdib.iBit / 8)))
        if imgdib.iWidth>0.0:
            cv2.namedWindow('OCR', cv2.WINDOW_NORMAL)
            cv2.putText(imgAngle, 'Dflection Angle:'+str(round(imgdib.angle,3)), (int(box[0])-10, max(20, int(box[1])-10)), cv2.FONT_HERSHEY_SIMPLEX, 2,
                        (255, 0, 0), 2)
            cv2.imshow('OCR', imgAngle)
            cv2.waitKey(0)
            dirpath = os.path.dirname(imgpath)
            foler = os.path.basename(dirpath) + '_angle'
            imgName = os.path.basename(imgpath).split('.')[0] + '_correction.' + os.path.basename(imgpath).split('.')[-1]
            dirpath = os.path.dirname(dirpath) + os.sep + foler
            if not os.path.exists(dirpath):
                os.mkdir(dirpath)
            savepath = os.path.join(dirpath, imgName)
            cv2.imwrite(savepath, imgAngle)
            self.imgName = 'OCR'
            cv2.namedWindow(self.imgName, cv2.WINDOW_NORMAL)
            self.img = imgAngle
            self.img3 = self.img.copy()
            cv2.setMouseCallback(self.imgName, self.on_mouse, 'ocr')
            cv2.imshow(self.imgName, self.img3)
            cv2.waitKey(0)
            ocr.OCR(savepath,self.boxes[0])
            self.boxes=[]
        else:
            QMessageBox.information(None, 'Remander', "Cannot recorrect this image.")
            return

    def creat2Model(self):
        if self.doublemodel != None:
            self.clear1Model(self.doublemodel)
        if self.tempdll ==None:
            self.tempdll = ctypes.windll.LoadLibrary(r"templatelocate.dll")
        self.tempdll.Init2ShapeModel.restype = c_void_p
        self.doublemodel = self.tempdll.Init2ShapeModel()
        self.tempdll.create2ShapeModel_Path.restype = c_bool
        rect1 = rect2i()
        box = self.boxes[0]
        rect1.x = box[0]
        rect1.y = box[1]
        rect1.width = box[2]
        rect1.height = box[3]
        rect2 = rect2i()
        box = self.boxes[1]
        rect2.x = box[0]
        rect2.y = box[1]
        rect2.width = box[2]
        rect2.height = box[3]
        imgpath = bytes(self.imgPath, 'utf-8')
        self.result1 = ResultPoint2d()
        self.result2 = ResultPoint2d()
        self.tempdll.create2ShapeModel_Path(ctypes.c_void_p(self.doublemodel), imgpath, rect1, rect2,
        ctypes.byref(self.result1), ctypes.byref(self.result2),c_double(0.0),c_double(360.0),c_double(0.6))
        self.save2Model()

    def baizhengImage(self,imgpath):

        self.tempdll.find2MatchModel_Path.retype = c_bool
        buffer = ImageDib()
        bimgpath = bytes(imgpath,'utf-8')
        self.tempdll.find2MatchModel_Path(ctypes.c_void_p(self.doublemodel),bimgpath,self.result1,
                                            self.result2,ctypes.byref(buffer),c_double(0.0),c_double(360.0),c_double(0.6))
        self.boxes=[]
        np_canny = np.array(np.fromiter(buffer.pBuffer, dtype=np.uint8, count=int(buffer.iWidth * buffer.iHeight*buffer.iBit/8)))
        np_canny=np_canny.reshape(( buffer.iHeight,buffer.iWidth,int(buffer.iBit/8)))
        if buffer.iWidth>0.0:
            cv2.namedWindow('result', cv2.WINDOW_NORMAL)
            cv2.imshow('result',np_canny)
            cv2.waitKey()
        else:
            QMessageBox.information(None,'Remander',"Cannot recorrect this image.")
            return
        dirpath = os.path.dirname(imgpath)
        foler = os.path.basename(dirpath)+'_correction'
        imgName = os.path.basename(imgpath).split('.')[0]+'_correction.'+os.path.basename(imgpath).split('.')[-1]
        dirpath = os.path.dirname(dirpath)+os.sep+foler
        if not os.path.exists(dirpath):
            os.mkdir(dirpath)
        savepath = os.path.join(dirpath,imgName)
        cv2.imwrite(savepath,np_canny)

    def save2Model(self):
        self.tempdll.Save2ShapeModel.retype = c_bool
        caption = CAPTION % __appname__
        path = QFileDialog.getSaveFileName(None, caption, '.', 'File (*.shm)')[0]
        if path == None or path == '':
            return
        pointPath = os.path.join(os.path.dirname(path), os.path.basename(path).split('.')[0]+ '_doubleTemplate1' + '.ini')
        self.saveResultPoint(pointPath)
        path = bytes(path,'utf-8')
        self.tempdll.Save2ShapeModel(path,c_void_p(self.doublemodel))

    def read2Model(self,path):
        if self.doublemodel != None:
            self.clear1Model(self.doublemodel)
        if self.tempdll ==None:
            self.tempdll = ctypes.windll.LoadLibrary(r"templatelocate.dll")
        self.tempdll.Init2ShapeModel.restype = c_void_p
        self.doublemodel = self.tempdll.Init2ShapeModel()
        self.tempdll.Read2ShapeModel.restype = c_bool
        pointPath = os.path.join(os.path.dirname(path),os.path.basename(path).split('.')[0]+'.ini')
        self.readResultPoint(pointPath)
        path = bytes(path, 'utf-8')
        readresult = self.tempdll.Read2ShapeModel(path,c_void_p(self.doublemodel))

    def saveResultPoint(self,path):
        config = configparser.ConfigParser()
        config['Result_Point1']={'x': str(self.result1.x),
            'y':str(self.result1.y), 'angle':str(self.result1.angle),
            'score': str(self.result1.score), 'scale':str(self.result1.scale)
        }
        config['Result_Point2'] = {'x': str(self.result2.x),
                                   'y': str(self.result2.y), 'angle': str(self.result2.angle),
                                   'score': str(self.result2.score), 'scale': str(self.result2.scale)
                                   }
        config.write(open(path, 'w'))
    def readResultPoint(self,path):
        self.result1 = ResultPoint2d()
        self.result2 = ResultPoint2d()
        config = configparser.ConfigParser()
        config.read(path)
        self.result1.x=float(config.get('Result_Point1', 'x'))
        self.result1.y =float(config.get('Result_Point1', 'y'))
        self.result1.score =float(config.get('Result_Point1', 'score'))
        self.result1.angle =float(config.get('Result_Point1', 'angle'))
        self.result1.scale =float(config.get('Result_Point1', 'scale'))
        self.result2.x =float(config.get('Result_Point2', 'x'))
        self.result2.y =float(config.get('Result_Point2', 'y'))
        self.result2.score =float(config.get('Result_Point2', 'score'))
        self.result2.angle =float(config.get('Result_Point2', 'angle'))
        self.result2.scale =float(config.get('Result_Point2', 'scale'))
    def clear2Model(self):
        self.tempdll.Read2ShapeModel.restype = c_voidp
        self.tempdll.Read2ShapeModel(c_void_p(self.doublemodel))


